package com.yc.sole.system.biz;

import cn.hutool.captcha.CaptchaUtil;
import cn.hutool.captcha.CircleCaptcha;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.crypto.digest.BCrypt;
import cn.hutool.http.useragent.UserAgent;
import cn.hutool.http.useragent.UserAgentUtil;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.yc.sole.common.constant.CacheConstant;
import com.yc.sole.common.constant.PubConstant;
import com.yc.sole.common.domain.UserInfo;
import com.yc.sole.common.enums.CommonState;
import com.yc.sole.common.enums.MenuType;
import com.yc.sole.common.enums.TrueOrFalse;
import com.yc.sole.framework.exception.BaseException;
import com.yc.sole.framework.redis.RedissonService;
import com.yc.sole.framework.redis.enums.CacheTime;
import com.yc.sole.framework.utils.IpUtil;
import com.yc.sole.framework.utils.TreeUtil;
import com.yc.sole.framework.utils.ValidateUtil;
import com.yc.sole.framework.web.SecurityAuthenticator;
import com.yc.sole.system.dto.ConfigDto;
import com.yc.sole.system.dto.LogDto;
import com.yc.sole.system.dto.MenuDto;
import com.yc.sole.system.dto.UserDto;
import com.yc.sole.system.exception.SysResultEnum;
import com.yc.sole.system.repository.ConfigRepository;
import com.yc.sole.system.repository.LogRepository;
import com.yc.sole.system.repository.UserRepository;
import com.yc.sole.system.request.LoginReq;
import com.yc.sole.system.response.MenuResp;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.util.StopWatch;

import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @author yizuomin
 * @date 2023/3/26 19:34
 **/
@Slf4j
@Service
@RequiredArgsConstructor
public class AuthBiz {

    private final UserRepository userRepository;
    private final RedissonService redissonService;
    private final LogRepository logRepository;
    private final ConfigRepository configRepository;
    private final SecurityAuthenticator securityAuthenticator;

    /**
     * 获取验证码
     *
     * @param sessionId r
     * @return r
     */
    public String captcha(String sessionId) {
        CircleCaptcha circleCaptcha = CaptchaUtil.createCircleCaptcha(130, 48, 4, 0);
        String verCode = circleCaptcha.getCode();
        // 存入redis并设置过期时间为3分钟
        redissonService.setString(CacheConstant.AUTH_CAPTCHA_KEY, sessionId, verCode, CacheTime.TWO_MINUTE);
        return circleCaptcha.getImageBase64Data();
    }

    /**
     * web登录
     *
     * @param loginReq
     * @param request
     * @return
     */
    public String webLogin(LoginReq loginReq, HttpServletRequest request) {
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        String token;
        String errorMessage = "";
        try {
            token = this.login(loginReq, request);
        } catch (Exception e) {
            errorMessage = e.getMessage();
            throw e;
        } finally {
            stopWatch.stop();
            //记录登录日志
            createLog(loginReq.getUsername(), request, stopWatch, errorMessage);
        }
        return token;
    }

    /**
     * 登录
     *
     * @param loginReq
     * @param request
     * @return
     */
    public String login(LoginReq loginReq, HttpServletRequest request) {
        //验证码value
        // String sessionId = loginReq.getSessionId();
        // String code = redissonService.getString(CacheConstant.AUTH_CAPTCHA_KEY, sessionId);
        // ValidateUtil.isBlank(code, SysResultEnum.AUTH_CAPTCHA_CODE_EXPIRE);
        // ValidateUtil.notEqualsIgnoreCase(loginReq.getVerifyCode(), code, SysResultEnum.AUTH_CAPTCHA_CODE_ERROR);
        //删除验证码
        // redissonService.removeString(CacheConstant.AUTH_CAPTCHA_KEY, sessionId);
        //查询用户信息
        UserDto userDto = userRepository.selectByUsernameOrPhone(loginReq.getUsername());
        ValidateUtil.isNull(userDto, SysResultEnum.AUTH_USER_NOT_FOUND);
        //验证用户状态
        ValidateUtil.notEqual(CommonState.ENABLE, userDto.getState(), SysResultEnum.AUTH_USER_IS_DISABLED);
        //验证密码
        if (!BCrypt.checkpw(loginReq.getPassword(), userDto.getPassword())) {
            throw new BaseException(SysResultEnum.AUTH_PASSWORD_ERROR);
        }
        UserInfo userInfo = BeanUtil.copyProperties(userDto, UserInfo.class);
        //查询用户角色权限
        if (CollUtil.isNotEmpty(userDto.getMenus())) {
            Set<String> permission = userDto.getMenus().stream().filter(menuDto -> MenuType.BUTTON.equals(menuDto.getMenuType()))
                    .map(MenuDto::getPath).collect(Collectors.toSet());
            List<MenuDto> menuDtos = userDto.getMenus().stream().filter(menuDto -> MenuType.MENU.equals(menuDto.getMenuType())).toList();
            List<MenuResp> menuResps = BeanUtil.copyToList(menuDtos, MenuResp.class);
            userInfo.setMenus(TreeUtil.listToTree(menuResps));
            userInfo.setPermissions(permission);
        }
        //更新登录时间
        UserDto updateDto = new UserDto();
        updateDto.setId(userDto.getId());
        updateDto.setLastLoginDate(DateUtil.now());
        userRepository.updateUserById(updateDto);
        //生成token
        String token = IdWorker.get32UUID();
        //获取系统配置
        ConfigDto configDto = configRepository.selectConfig();
        if (Objects.nonNull(configDto) && CharSequenceUtil.isNotBlank(configDto.getEnterpriseName())) {
            userInfo.setEnterpriseName(configDto.getEnterpriseName());
            userInfo.setQrCodeUrl(configDto.getQrCodeUrl());
        } else {
            userInfo.setEnterpriseName("请设置企业名称");
        }
        //将用户信息放入缓存
        this.getIpInfo(userInfo, request);
        userInfo.setToken(token);
        securityAuthenticator.login(token, userInfo);
        return token;
    }

    /**
     * 记录日志
     *
     * @param request
     * @param stopWatch
     * @param errorMessage
     */
    private void createLog(String username, HttpServletRequest request, StopWatch stopWatch, String errorMessage) {
        Long userId = userRepository.selectUserIdByUsername(username);
        if (Objects.nonNull(userId)) {
            LogDto logDto = new LogDto();
            String ipAddress = IpUtil.getIpAddress(request);
            logDto.setIp(ipAddress);
            IpUtil.IPInfo region = IpUtil.getRegion(ipAddress);
            logDto.setAddress(region.getAddress() + "_" + region.getIsp());
            logDto.setUserId(userId);
            logDto.setUsername(username);
            logDto.setUri(request.getRequestURI());
            logDto.setMethodName("登录");
            logDto.setRequestTime(DateUtil.now());
            logDto.setExecutionTime(stopWatch.getTotalTimeMillis());
            logDto.setErrorFlag(CharSequenceUtil.isNotBlank(errorMessage) ? TrueOrFalse.TRUE : TrueOrFalse.FALSE);
            logDto.setRequest("");
            logDto.setErrorMessage(errorMessage);
            logRepository.saveLog(logDto);
        }
    }

    /**
     * 获取当前用户信息
     *
     * @return u
     */
    public UserInfo userInfo(HttpServletRequest request) {
        String token = request.getHeader(PubConstant.TOKEN_HEADER);
        return securityAuthenticator.getUserInfo(token);
    }

    /**
     * 登出
     */
    public void logout(HttpServletRequest request) {
        securityAuthenticator.logout(request);
    }

    /**
     * @param userInfo
     * @param request
     */
    private void getIpInfo(UserInfo userInfo, HttpServletRequest request) {
        String ip = IpUtil.getIpAddress(request);
        IpUtil.IPInfo region = IpUtil.getRegion(ip);
        userInfo.setAddress(region.getAddress());
        userInfo.setIsp(region.getIsp());
        UserAgent userAgent = UserAgentUtil.parse(request.getHeader("User-Agent"));
        userInfo.setIp(ip);
        userInfo.setOs(userAgent.getPlatform().getName() + userAgent.getOsVersion());
        userInfo.setBrowser(userAgent.getBrowser().getName());
        //Map<String, Object> map = new HashMap<>(2);
        //String path = "https://way.jd.com/Quxun/ipaddress";
        //map.put("ipaddress", ip);
        //map.put("appkey", "278782cf0c1a0442af27ed86d297ca03");
        //try {
        //    String resp = HttpUtil.get(path, map);
        //    JSONObject jsonObject = JSONUtil.parseObj(resp);
        //    JSONObject result = jsonObject.getJSONObject("result");
        //    JSONObject data = result.getJSONObject("data");
        //    String city = data.getStr("address_city");
        //    String region = data.getStr("address_province");
        //    String isp = data.getStr("address_isp");
        //    String country = data.getStr("address_country");
        //    userInfo.setAddress(country + "|" + region + "|" + city);
        //    userInfo.setIsp(isp);
        //    return userInfo;
        //} catch (Exception e) {
        //    log.error("ip接口异常，原因：{}", e.getMessage());
        //}
    }
}
